﻿// Copyright (c) Yoganand R. All rights reserved.
// For continued development and updates, visit http://yogsbreath.com
using System;
using System.Web.UI;
using System.ComponentModel;
using System.Text;
using System.Collections.Generic;

namespace MVCnExt.Web.UI.Ext
{
    /// <summary>
    /// An abstraction layer which allows the authoring of ScriptControl objects
    /// which will work for both MVC applications as well as WebForms applications
    /// </summary>
    public abstract class ScriptManagerBase : Control, IPostBackDataHandler, IScriptManager
    {
        private ClientScriptManagerBase _clientScript;
        List<IScriptControl> _scriptControls = new List<IScriptControl>();
        List<ServiceReference> _services = new List<ServiceReference>();


        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            if (base.DesignMode)
                return;

            if (GetCurrent(Page) != null)
            {
                throw new InvalidOperationException("Only one script manager per page allowed.");
            }

            Page.Items[typeof(ScriptManagerBase)] = this;

            Page.PreRenderComplete += new EventHandler(OnPagePreRenderComplete);
            Page.InitComplete += new EventHandler(OnPageInitComplete);
        }

        private void OnPageInitComplete(object sender, EventArgs e)
        {
            if (base.DesignMode)
                return;

            if (Page.Form == null)
            {
                //need formless script manager
                _clientScript = new FormlessClientScriptManager(Page);
            }
            else
            {
                //load standard script manager (ClientScriptManager)
                _clientScript = new ClientScriptManagerWrapper(Page);
            }
        }

        public static ScriptManagerBase GetCurrent(Page page)
        {
            if (page == null)
            {
                throw new ArgumentNullException("page");
            }

            ScriptManagerBase scriptManager = (page.Items[typeof(ScriptManagerBase)] as ScriptManagerBase);
            if (scriptManager == null)
            {
                ScriptManager sm = page.Items[typeof(ScriptManager)] as ScriptManager;
                if(sm != null)
                    scriptManager = new ScriptManagerWrapper(sm);
            }

            return scriptManager;
        }

        public virtual ClientScriptManagerBase ClientScript
        {
            get
            {
                return _clientScript;
            }
        }

        #region IPostBackDataHandler Members

        public virtual bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
        {
            throw new NotImplementedException();
        }

        public virtual void RaisePostDataChangedEvent()
        {
            throw new NotImplementedException();
        }

        #endregion

        #region IScriptManager Members

        public virtual void RegisterArrayDeclaration(Control control, string arrayName, string arrayValue)
        {
            _clientScript.RegisterArrayDeclaration(arrayName, arrayValue);
        }

        public virtual void RegisterClientScriptBlock(Control control, Type type, string key, string script, bool addScriptTags)
        {
            _clientScript.RegisterClientScriptBlock(type, key, script, addScriptTags);
        }

        public virtual void RegisterClientScriptInclude(Control control, Type type, string key, string url)
        {
            _clientScript.RegisterClientScriptInclude(type, key, url);
        }

        public virtual void RegisterClientScriptResource(Control control, Type type, string resourceName)
        {
            throw new NotSupportedException();

            //can't support this quite yet until I can figure out how to get the resource and get its URL
            //_clientScript.RegisterClientScriptResource(type, resourceName);
        }

        public virtual void RegisterDispose(Control control, string disposeScript)
        {
            throw new NotSupportedException();
        }

        public virtual void RegisterExpandoAttribute(Control control, string controlId, string attributeName, string attributeValue, bool encode)
        {
            _clientScript.RegisterExpandoAttribute(controlId, attributeName, attributeValue, encode);
        }

        public virtual void RegisterHiddenField(Control control, string hiddenFieldName, string hiddenFieldValue)
        {
            _clientScript.RegisterHiddenField(hiddenFieldName, hiddenFieldValue);
        }

        public virtual void RegisterOnSubmitStatement(Control control, Type type, string key, string script)
        {
            _clientScript.RegisterOnSubmitStatement(type, key, script);
        }

        public virtual void RegisterPostBackControl(Control control)
        {
            throw new NotSupportedException();
        }

        public virtual void RegisterStartupScript(Control control, Type type, string key, string script, bool addScriptTags)
        {
            _clientScript.RegisterStartupScript(type, key, script, addScriptTags);
        }

        public virtual void SetFocus(string clientID)
        {
            throw new NotSupportedException();
        }

        public virtual void SetFocus(Control control)
        {
            throw new NotSupportedException();
        }

        public virtual bool IsInAsyncPostBack
        {
            get
            {
                throw new NotSupportedException();
            }
        }

        public virtual bool SupportsPartialRendering
        {
            get { return false; }
        }

        public virtual void RegisterAsyncPostBackControl(Control control)
        {
            throw new NotSupportedException();
        }

        public virtual void RegisterExtenderControl<TExtenderControl>(TExtenderControl extenderControl, Control targetControl) where TExtenderControl : Control, IExtenderControl
        {
            throw new NotSupportedException();
        }

        public virtual void RegisterProxy(ScriptManagerProxy proxy)
        {
            throw new NotSupportedException();
        }

        public virtual void RegisterScriptControl<TScriptControl>(TScriptControl scriptControl) where TScriptControl : Control, IScriptControl
        {
            _scriptControls.Add(scriptControl);
        }

        public virtual void RegisterScriptDescriptors(IExtenderControl extenderControl)
        {
            throw new NotSupportedException();
        }

        public virtual void RegisterScriptDescriptors(IScriptControl scriptControl)
        {
            //This method may be perfect place to create a single file for page output

            IEnumerable<ScriptDescriptor> descriptors = scriptControl.GetScriptDescriptors();

            StringBuilder script = new StringBuilder();
            foreach (ScriptDescriptor desc in descriptors)
            {
                script.AppendLine(((ScriptControlDescriptorBase)desc).WriteScript());
            }

            _clientScript.RegisterStartupScript(scriptControl.GetType(),
                ((Control)scriptControl).ClientID + "PageScript",
                script.ToString(), true);
        }

        public virtual void RegisterUpdatePanel(UpdatePanel updatePanel)
        {
            throw new NotSupportedException();
        }

        public virtual void UnregisterUpdatePanel(UpdatePanel updatePanel)
        {
            throw new NotSupportedException();
        }

        public virtual string AsyncPostBackSourceElementID
        {
            get
            {
                throw new NotSupportedException();
            }
        }

        #endregion

        private void OnPagePreRenderComplete(object sender, EventArgs e)
        {
            //RegisterGlobalizationScriptBlock();
            RegisterScripts();
            //RegisterServices();
        }

        private void RegisterGlobalizationScriptBlock()
        {
            //TODO: enable globalization
            throw new NotImplementedException();
        }

        /// <summary>
        /// Calls GetScriptReference() for each registered IScriptControl
        /// </summary>
        private void RegisterScripts()
        {
            List<ScriptReference> scripts = new List<ScriptReference>();

            //if we ever add support for proxies, add their scripts here

            foreach (IScriptControl ctrl in _scriptControls)
            {
                IEnumerable<ScriptReference> references = ctrl.GetScriptReferences();

                RegisterScriptReferences(references);
            }
        }

        /// <summary>
        /// Registers a list of ScriptReference objects with the page
        /// </summary>
        public void RegisterScriptReferences(IEnumerable<ScriptReference> references)
        {
            foreach (ScriptReference reference in references)
            {
                // check to see if script has already been registered
                if (!ClientScript.IsClientScriptIncludeRegistered(reference.Path))
                {
                    // make sure scripts are registered properly
                    if (reference.Path.IndexOf("WebResource.axd") != 0)
                    {
                        // we don't need to call ResolveClientUrl
                        ClientScript.RegisterClientScriptInclude(reference.Path,
                            reference.Path);
                    }
                    else
                    {
                        // resolve client url for WebResource.axd file
                        ClientScript.RegisterClientScriptInclude(reference.Path,
                            ResolveClientUrl(reference.Path));
                    }
                }
            }
        }


        private void RegisterServices()
        {
            //TODO: register web services so client controls can reference them
            throw new NotImplementedException();

            //NOTE: no plans to support PageMethods or Proxy controls at this time
        }
    }

}
